package com.example.smartwaterapi.utils;

import com.volcengine.tos.TOSClientConfiguration;
import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.auth.StaticCredentials;
import com.volcengine.tos.model.object.*;
import com.volcengine.tos.model.bucket.*;
import com.volcengine.tos.comm.common.ACLType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * 火山引擎对象存储工具类
 */
@Component
@Slf4j
public class TosClientUtils {

    @Value("${tos.endpoint}")
    private String endpoint;

    @Value("${tos.region}")
    private String region;

    @Value("${tos.accessKey}")
    private String accessKey;

    @Value("${tos.secretKey}")
    private String secretKey;

    @Value("${tos.bucket}")
    private String bucketName;

    private TOSV2 tosClient;

    @PostConstruct
    public void init() {
        try {
            // 使用TOSClientConfiguration创建客户端
            TOSClientConfiguration configuration = TOSClientConfiguration.builder()
                    .region(region)
                    .endpoint(endpoint)
                    .credentials(new StaticCredentials(accessKey, secretKey))
                    .build();
            
            tosClient = new TOSV2ClientBuilder().build(configuration);
            log.info("TOS客户端初始化成功");
        } catch (Exception e) {
            log.error("TOS客户端初始化失败", e);
            throw new RuntimeException("TOS客户端初始化失败", e);
        }
        
        // 设置桶为公开可读
        setBucketPublicRead();
    }

    /**
     * 设置桶为公开可读
     */
    private void setBucketPublicRead() {
        try {
            // 直接设置桶ACL为公开可读
            PutBucketACLInput putBucketAclInput = new PutBucketACLInput()
                    .setBucket(bucketName)
                    .setAcl(ACLType.ACL_PUBLIC_READ);
            
            tosClient.putBucketACL(putBucketAclInput);
            log.info("桶 {} 已设置为公开可读", bucketName);
            
        } catch (Exception e) {
            log.warn("设置桶公开可读权限失败，可能需要手动配置: {}", e.getMessage());
        }
    }

    /**
     * 上传文件流 - 不设置对象ACL，让对象继承桶权限
     */
    public PutObjectOutput uploadStream(String objectKey, InputStream inputStream, long contentLength) {
        try {
            log.info("开始上传流: {} to bucket: {}", objectKey, bucketName);
            
            // 不设置ACL，让对象继承桶的权限设置
            PutObjectInput input = new PutObjectInput()
                    .setBucket(bucketName)
                    .setKey(objectKey)
                    .setContent(inputStream)
                    .setContentLength(contentLength);
            
            PutObjectOutput result = tosClient.putObject(input);
            log.info("上传流成功: {} (继承桶权限)", objectKey);
            return result;
        } catch (Exception e) {
            log.error("上传流失败: {} to bucket: {}, 错误: {}", objectKey, bucketName, e.getMessage(), e);
            throw new RuntimeException("上传流失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传字符串内容 - 不设置对象ACL，让对象继承桶权限
     */
    public PutObjectOutput uploadString(String objectKey, String content) {
        try {
            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
            log.info("开始上传字符串: {} to bucket: {}, 大小: {} bytes", objectKey, bucketName, contentBytes.length);
            
            // 不设置ACL，让对象继承桶的权限设置
            PutObjectInput input = new PutObjectInput()
                    .setBucket(bucketName)
                    .setKey(objectKey)
                    .setContent(new ByteArrayInputStream(contentBytes))
                    .setContentLength(contentBytes.length);
            
            PutObjectOutput result = tosClient.putObject(input);
            log.info("上传字符串成功: {} (继承桶权限)", objectKey);
            return result;
        } catch (Exception e) {
            log.error("上传字符串失败: {} to bucket: {}, 错误: {}", objectKey, bucketName, e.getMessage(), e);
            throw new RuntimeException("上传字符串失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传文件 - 不设置对象ACL，让对象继承桶权限
     */
    public PutObjectOutput uploadFile(String objectKey, File file) {
        try {
            log.info("开始上传文件: {} to bucket: {}", objectKey, bucketName);
            
            // 不设置ACL，让对象继承桶的权限设置
            PutObjectInput input = new PutObjectInput()
                    .setBucket(bucketName)
                    .setKey(objectKey)
                    .setContent(new FileInputStream(file))
                    .setContentLength(file.length());
            
            PutObjectOutput result = tosClient.putObject(input);
            log.info("上传文件成功: {} (继承桶权限)", objectKey);
            return result;
        } catch (Exception e) {
            log.error("上传文件失败: {} to bucket: {}, 错误: {}", objectKey, bucketName, e.getMessage(), e);
            throw new RuntimeException("上传文件失败: " + e.getMessage(), e);
        }
    }

    /**
     * 下载对象到输入流
     */
    public GetObjectV2Output downloadObject(String objectKey) {
        try {
            log.info("开始下载对象: {} from bucket: {}", objectKey, bucketName);
            
            GetObjectV2Input input = new GetObjectV2Input()
                    .setBucket(bucketName)
                    .setKey(objectKey);
            GetObjectV2Output result = tosClient.getObject(input);
            
            log.info("下载对象成功: {}, Content-Length: {}", objectKey, result.getContentLength());
            return result;
        } catch (Exception e) {
            log.error("下载对象失败: {} from bucket: {}, 错误: {}", objectKey, bucketName, e.getMessage(), e);
            throw new RuntimeException("下载对象失败: " + e.getMessage(), e);
        }
    }

    /**
     * 删除对象
     */
    public void deleteObject(String objectKey) {
        try {
            DeleteObjectInput input = new DeleteObjectInput()
                    .setBucket(bucketName)
                    .setKey(objectKey);
            tosClient.deleteObject(input);
            log.info("删除对象成功: {}", objectKey);
        } catch (Exception e) {
            log.error("删除对象失败: {}", e.getMessage(), e);
            throw new RuntimeException("删除对象失败", e);
        }
    }

    /**
     * 检查对象是否存在
     */
    public boolean objectExists(String objectKey) {
        try {
            HeadObjectV2Input input = new HeadObjectV2Input()
                    .setBucket(bucketName)
                    .setKey(objectKey);
            
            tosClient.headObject(input);
            return true;
        } catch (Exception e) {
            log.debug("对象不存在: {}", objectKey);
            return false;
        }
    }

    /**
     * 设置桶ACL权限
     */
    public void setBucketACL(ACLType aclType) {
        try {
            PutBucketACLInput input = new PutBucketACLInput()
                    .setBucket(bucketName)
                    .setAcl(aclType);
            
            tosClient.putBucketACL(input);
            log.info("设置桶ACL成功: {} -> {}", bucketName, aclType);
        } catch (Exception e) {
            log.error("设置桶ACL失败: {}", bucketName, e);
            throw new RuntimeException("设置桶ACL失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取桶ACL权限 - 简化版本，返回默认值
     */
    public ACLType getBucketACL() {
        try {
            // 由于API问题，暂时返回默认值
            // 实际项目中可以通过其他方式获取桶权限
            log.info("获取桶ACL权限: {} (默认返回PUBLIC_READ)", bucketName);
            return ACLType.ACL_PUBLIC_READ;
        } catch (Exception e) {
            log.error("获取桶ACL失败: {}", bucketName, e);
            return ACLType.ACL_PUBLIC_READ; // 返回默认值
        }
    }

    /**
     * 获取对象ACL权限 - 简化版本，返回默认值
     */
    public ACLType getObjectACL(String objectKey) {
        try {
            // 由于API问题，暂时返回默认值
            // 实际项目中对象会继承桶的权限
            log.info("获取对象ACL权限: {} (默认返回PUBLIC_READ)", objectKey);
            return ACLType.ACL_PUBLIC_READ;
        } catch (Exception e) {
            log.error("获取对象ACL失败: {}", objectKey, e);
            return ACLType.ACL_PUBLIC_READ; // 返回默认值
        }
    }

    /**
     * 设置对象ACL权限 - 简化版本
     */
    public void setObjectACL(String objectKey, ACLType aclType) {
        try {
            // 由于API问题，暂时只记录日志
            // 实际项目中对象会继承桶的权限，通常不需要单独设置
            log.info("设置对象ACL权限: {} -> {} (实际继承桶权限)", objectKey, aclType);
        } catch (Exception e) {
            log.error("设置对象ACL失败: {}", objectKey, e);
            throw new RuntimeException("设置对象ACL失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取对象的URL
     * 注意：这里返回的是公共访问URL，实际访问权限取决于桶的ACL设置
     *
     * @param objectKey 对象键
     * @return 对象URL
     */
    public String getObjectUrl(String objectKey) {
        return String.format("https://%s.%s/%s", bucketName, endpoint, objectKey);
    }

    /**
     * 获取桶名称
     */
    public String getBucketName() {
        return bucketName;
    }
}